#!/bin/bash

### Constants
PLAT="$(grep -sEe '^NAME\=' /etc/os-release \
  | sed -E -e "s/NAME\=[\'\"]?([^ ]*).*/\1/")"

# dual protocol, VPN type supplied as $1
VPN="${1}"
setupVars="/etc/pivpn/${VPN}/setupVars.conf"
ERR=0

### Functions
err() {
  echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}

### Script
if [[ ! -f "${setupVars}" ]]; then
  err "::: Missing setup vars file!"
  exit 1
fi

# SC1090 disabled as setupVars file differs from system to system
# shellcheck disable=SC1090
source "${setupVars}"

if [[ "${VPN}" == "wireguard" ]]; then
  VPN_PRETTY_NAME="WireGuard"
  VPN_SERVICE="wg-quick@wg0"

  if [[ "${PLAT}" == 'Alpine' ]]; then
    VPN_SERVICE='wg-quick'
  fi
elif [[ "${VPN}" == "openvpn" ]]; then
  VPN_SERVICE="openvpn"
  VPN_PRETTY_NAME="OpenVPN"
fi

if [[ "$(< /proc/sys/net/ipv4/ip_forward)" -eq 1 ]]; then
  echo ":: [OK] IP forwarding is enabled"
else
  ERR=1
  read -r \
    -p ":: [ERR] IP forwarding is not enabled, attempt fix now? [Y/n] " \
    REPLY

  if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
    sed -i '/net.ipv4.ip_forward=1/s/^#//g' /etc/sysctl.conf
    sysctl -p
    echo "Done"
  fi
fi

if [[ "${USING_UFW}" -eq 0 ]]; then
  # Disabled SC Warnings for SC2154, values
  # for variables are sourced from setupVars
  # shellcheck disable=SC2154
  if iptables \
    -t nat \
    -C POSTROUTING \
    -s "${pivpnNET}/${subnetClass}" \
    -o "${IPv4dev}" \
    -j MASQUERADE \
    -m comment \
    --comment "${VPN}-nat-rule" &> /dev/null; then
    echo ":: [OK] Iptables MASQUERADE rule set"
  else
    ERR=1
    echo -n ":: [ERR] Iptables MASQUERADE rule is not set, "
    echo -n "attempt fix now? [Y/n] "
    read -r REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      iptables \
        -t nat \
        -I POSTROUTING \
        -s "${pivpnNET}/${subnetClass}" \
        -o "${IPv4dev}" \
        -j MASQUERADE \
        -m comment \
        --comment "${VPN}-nat-rule"

      iptables-save > /etc/iptables/rules.v4
      echo "Done"
    fi
  fi

  if [[ "${INPUT_CHAIN_EDITED}" -eq 1 ]]; then
    # Disabled SC Warnings for SC2154, values
    # for variables are sourced from setupVars
    # shellcheck disable=SC2154
    if iptables \
      -C INPUT \
      -i "${IPv4dev}" \
      -p "${pivpnPROTO}" \
      --dport "${pivpnPORT}" \
      -j ACCEPT \
      -m comment \
      --comment "${VPN}-input-rule" &> /dev/null; then
      echo ":: [OK] Iptables INPUT rule set"
    else
      ERR=1
      read -r \
        -p ":: [ERR] Iptables INPUT rule is not set, attempt fix now? [Y/n] " \
        REPLY

      if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
        iptables \
          -I INPUT 1 \
          -i "${IPv4dev}" \
          -p "${pivpnPROTO}" \
          --dport "${pivpnPORT}" \
          -j ACCEPT \
          -m comment \
          --comment "${VPN}-input-rule"

        iptables-save > /etc/iptables/rules.v4
        echo "Done"
      fi
    fi
  fi

  if [[ "${FORWARD_CHAIN_EDITED}" -eq 1 ]]; then
    # Disabled SC Warnings for SC2154, values
    # for variables are sourced from setupVars
    # shellcheck disable=SC2154
    if iptables \
      -C FORWARD \
      -s "${pivpnNET}/${subnetClass}" \
      -i "${pivpnDEV}" \
      -o "${IPv4dev}" \
      -j ACCEPT \
      -m comment \
      --comment "${VPN}-forward-rule" &> /dev/null; then
      echo ":: [OK] Iptables FORWARD rule set"
    else
      ERR=1
      echo -n ":: [ERR] Iptables FORWARD rule is not set, "
      echo -n "attempt fix now? [Y/n] "
      read -r REPLY

      if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
        iptables \
          -I FORWARD 1 \
          -d "${pivpnNET}/${subnetClass}" \
          -i "${IPv4dev}" \
          -o "${pivpnDEV}" \
          -m conntrack \
          --ctstate RELATED,ESTABLISHED \
          -j ACCEPT \
          -m comment \
          --comment "${VPN}-forward-rule"

        iptables \
          -I FORWARD 2 \
          -s "${pivpnNET}/${subnetClass}" \
          -i "${pivpnDEV}" \
          -o "${IPv4dev}" \
          -j ACCEPT \
          -m comment \
          --comment "${VPN}-forward-rule"

        iptables-save > /etc/iptables/rules.v4
        echo "Done"
      fi
    fi
  fi
else
  if LANG="en_US.UTF-8" ufw status | grep -qw 'active'; then
    echo ":: [OK] Ufw is enabled"
  else
    ERR=1
    echo -n ":: [ERR] Ufw is not enabled, "
    echo -n "try to enable now? [Y/n] "
    read -r REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      ufw enable
    fi
  fi

  if iptables \
    -t nat \
    -C POSTROUTING \
    -s "${pivpnNET}/${subnetClass}" \
    -o "${IPv4dev}" \
    -j MASQUERADE \
    -m comment \
    --comment "${VPN}-nat-rule" &> /dev/null; then
    echo ":: [OK] Iptables MASQUERADE rule set"
  else
    ERR=1
    echo -n ":: [ERR] Iptables MASQUERADE rule is not set, "
    echo -n "attempt fix now? [Y/n] "
    read -r REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      sed_pattern='/delete these required/i'
      sed_pattern="${sed_pattern} *nat\n:POSTROUTING ACCEPT [0:0]\n"
      sed_pattern="${sed_pattern} -I POSTROUTING"
      sed_pattern="${sed_pattern} -s ${pivpnNET}/${subnetClass}"
      sed_pattern="${sed_pattern} -o ${IPv4dev}"
      sed_pattern="${sed_pattern} -j MASQUERADE"
      sed_pattern="${sed_pattern} -m comment"
      sed_pattern="${sed_pattern} --comment ${VPN}-nat-rule\n"
      sed_pattern="${sed_pattern}COMMIT\n"

      sed "${sed_pattern}" -i /etc/ufw/before.rules
      ufw reload
      echo "Done"
      unset sed_pattern
    fi
  fi

  if iptables \
    -C ufw-user-input \
    -p "${pivpnPROTO}" \
    --dport "${pivpnPORT}" \
    -j ACCEPT &> /dev/null; then
    echo ":: [OK] Ufw input rule set"
  else
    ERR=1
    read -r \
      -p ":: [ERR] Ufw input rule is not set, attempt fix now? [Y/n] " \
      REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      ufw insert 1 allow "${pivpnPORT}"/"${pivpnPROTO}"
      ufw reload
      echo "Done"
    fi
  fi

  if iptables \
    -C ufw-user-forward \
    -i "${pivpnDEV}" \
    -o "${IPv4dev}" \
    -s "${pivpnNET}/${subnetClass}" \
    -j ACCEPT &> /dev/null; then
    echo ":: [OK] Ufw forwarding rule set"
  else
    ERR=1
    read -r \
      -p ":: [ERR] Ufw forwarding rule is not set, attempt fix now? [Y/n] " \
      REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      ufw route insert 1 allow in on "${pivpnDEV}" \
        from "${pivpnNET}/${subnetClass}" out on "${IPv4dev}" to any
      ufw reload
      echo "Done"
    fi
  fi
fi

if [[ "${PLAT}" == 'Alpine' ]]; then
  if [[ "$(rc-service "${VPN_SERVICE}" status \
    | sed -E -e 's/.*status\: (.*)/\1/')" == 'started' ]]; then
    echo ":: [OK] ${VPN_PRETTY_NAME} is running"
  else
    ERR=1
    echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not running, "
    echo -n "try to start now? [Y/n] "
    read -r REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      rc-service -s "${VPN_SERVICE}" restart
      rc-service -N "${VPN_SERVICE}" start
      echo "Done"
    fi
  fi

  if rc-update show default \
    | grep -sEe "\s*${VPN_SERVICE} .*" &> /dev/null; then
    echo -n ":: [OK] ${VPN_PRETTY_NAME} is enabled "
    echo "(it will automatically start on reboot)"
  else
    ERR=1
    echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not enabled, "
    echo -n "try to enable now? [Y/n] "
    read -r REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      rc-update add "${VPN_SERVICE}" default
      echo "Done"
    fi
  fi
else
  if systemctl is-active -q "${VPN_SERVICE}"; then
    echo ":: [OK] ${VPN_PRETTY_NAME} is running"
  else
    ERR=1
    echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not running, "
    echo -n "try to start now? [Y/n] "
    read -r REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      systemctl start "${VPN_SERVICE}"
      echo "Done"
    fi
  fi

  if systemctl is-enabled -q "${VPN_SERVICE}"; then
    echo ":: [OK] ${VPN_PRETTY_NAME} is enabled "
    echo "(it will automatically start on reboot)"
  else
    ERR=1
    echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not enabled, "
    echo -n "try to enable now? [Y/n] "
    read -r REPLY

    if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
      systemctl enable "${VPN_SERVICE}"
      echo "Done"
    fi
  fi
fi

# grep -w (whole word) is used so port 11940 won't match when looking for 1194
if netstat -antu | grep -wqE "${pivpnPROTO}.*${pivpnPORT}"; then
  echo -n ":: [OK] ${VPN_PRETTY_NAME} is listening "
  echo "on port ${pivpnPORT}/${pivpnPROTO}"
else
  ERR=1
  echo -n ":: [ERR] ${VPN_PRETTY_NAME} is not listening, "
  echo -n "try to restart now? [Y/n] "
  read -r REPLY

  if [[ "${REPLY}" =~ ^[Yy]$ ]] || [[ -z "${REPLY}" ]]; then
    if [[ "${PLAT}" == 'Alpine' ]]; then
      rc-service -s "${VPN_SERVICE}" restart
      rc-service -N "${VPN_SERVICE}" start
    else
      systemctl restart "${VPN_SERVICE}"
    fi

    echo "Done"
  fi
fi

if [[ "${ERR}" -eq 1 ]]; then
  echo -e "[INFO] Run \e[1mpivpn -d\e[0m again to see if we detect issues"
fi
